package com.apes.scm.sal.saleReturn;

import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.generator.service.SequenceService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.util.EventUtil;
import com.apes.framework.util.LogicalUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.account.ledger.service.LedgerService;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.sal.saleOrder.SaleOrder;
import com.apes.scm.sal.saleOrder.SaleOrderItem;
import com.apes.scm.sal.saleOrder.SaleOrderItemRepository;
import com.apes.scm.sal.saleOrder.SaleOrderRepository;
import com.apes.scm.stock.transfer.model.Pick;
import com.apes.scm.stock.transfer.model.PickItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service("saleReturnWithOrderService")
public class SaleReturnWithOrderService extends DomainService {
    @Autowired
    SaleReturnRepository saleReturnRepository;
    @Autowired
    SaleReturnItemRepository saleReturnItemRepository;
    @Autowired
    SaleOrderItemRepository saleOrderItemRepository;
    @Autowired
    LedgerService ledgerService;
    @Autowired
    ProductAccountService productAccountService;
    @Autowired
    SaleOrderRepository saleOrderRepository;
    @Autowired
    private SequenceService sequenceService;
    @Autowired
    private PartyRoleRepository partyRoleRepository;

    /***
     * 功能: 创建
     * @param request
     * @returns
     */
    public SaleReturn create(SimpleRequest request) {

        SaleReturn saleReturn = request.getO(SaleReturn.class);
        String companyId = request.getCurrentCompany() == null ? "" : ((PartyRole)request.getCurrentCompany()).getId();

        saleReturn.setId("FT" + companyId + sequenceService.getId(SaleReturn.CONST_TABLE_NAME));
        // 判断明细是否为空
        if (saleReturn.getSaleReturnItems().size() == 0) throw new RuntimeException("退货明细不能为空");

        //发票限制
        if (saleReturn.getSaleOrder().getInvoicedAmount() != 0){
            throw new RuntimeException("该分销单已开发票，如需冲红请联系财务收回发票号码！");
        }

        // 回写会员扩展表逻辑
        if (saleReturn.getSaleOrder() != null && saleReturn.getSaleOrder().getFnCustomerExpandId() != null){
            saleReturn.setFnCustomerExpandId(saleReturn.getSaleOrder().getFnCustomerExpandId());
        }

        saleReturn.computeDiscount(); // 计算返利
        saleReturn.computeAmt(); // 合计金额
        saleReturn.setInvoiceStatus("no");
        saleReturn.setState("sent");
        setQtyReturning(saleReturn, 1.00); // 回写分销订单退货中数量

        // 冻结交货单(针对未发货数量)
        frost(saleReturn, 1.00);

        return saleReturnRepository.saveAndFlush(saleReturn);
    }


    /***
     * 功能： 修改
     * @param request
     * @return
     */
    public SaleReturn update(SimpleRequest request) {
        SaleReturn saleReturn = request.getO(SaleReturn.class);
        //发票限制
        if (saleReturn.getSaleOrder().getInvoicedAmount() != 0){
            throw new RuntimeException("该分销单已开发票，如需冲红请联系财务收回发票号码！");
        }

        SaleReturn oldSaleReturn = saleReturnRepository.findOne(saleReturn.getId());

        // 分销订单退货中数量释放与写入
        setQtyReturning(oldSaleReturn, -1.00);
        setQtyReturning(saleReturn, 1.00);

        saleReturn.computeDiscount(); // 计算返利
        saleReturn.computeAmt(); // 合计金额


        // 交货单的解冻与冻结(针对未发货数量)
        frost(oldSaleReturn, -1.00);
        frost(saleReturn, 1.00);

        return saleReturnRepository.saveAndFlush(saleReturn);
    }

    /***
     * 功能：删除
     * @param request
     * @return
     */
    public String delete(SimpleRequest request) {
        String id = request.get("id");
        SaleReturn saleReturn = saleReturnRepository.findOne(id);
        if (saleReturn == null) throw new RuntimeException("订单：" + request.get("id") + " 在系统中不存在。");
        if (saleReturn.getState().equals("confirmed"))
            throw new RuntimeException("订单：" + request.get("id") + " 在系统中已审批。");

        // 解冻交货单(针对未发货数量)
        frost(saleReturn, -1.00);

        // 分销订单退货中数量释放
        setQtyReturning(saleReturn, -1.00);

        saleReturnRepository.delete(saleReturn);
        return "删除成功";
    }

    /***
     * 功能：审核
     * @param request
     * @return
     */
    public SaleReturn approve(SimpleRequest request) {

        String id = request.get("id");
        SaleReturn saleReturn = saleReturnRepository.findOne(id);
        if (saleReturn == null) throw new RuntimeException("订单：" + id + " 在系统中不存在。");
        if (saleReturn.getVersion() != (int) request.get("version")) throw new RuntimeException("记录已更新或已删除，请重新提交！");
        if (saleReturn.getState().equals("confirmed")) throw new RuntimeException("订单：" + id + " 在系统中已审批。");


        // 返利金减少冻结项,增加未清项
        transaction(saleReturn, "discount_freeze", -1 * saleReturn.getDiscount(), "discount_unsettled", saleReturn.getDiscount());

        // 加可用数(针对未发货数量)
        saleReturn.getSaleReturnItems().stream().forEach((saleReturnItem ->{
            if (saleReturnItem.getQtyDelivering() > 0 &&checkPicked(saleReturnItem)) {
                productAccountService(saleReturn, saleReturnItem, 1.00, "分销提单冲红");
            }
        }));

        setQtyReturned(saleReturn);

        // 交货单先解冻 后终止(针对未发货数量)
        frost(saleReturn, -1.00);
        pickCancel(saleReturn);

        saleReturn.setState("confirmed");
        saleReturn.setDateApprove(new Date());
        SaleReturn nSaleReturn = saleReturnRepository.saveAndFlush(saleReturn);

        nSaleReturn.setShipped(); // 判断订单是否完成
        if (nSaleReturn.getState().equals("done")) nSaleReturn = saleReturnRepository.saveAndFlush(nSaleReturn);
        return nSaleReturn;
    }

    /***
     * 分销退货完成时减少占款未清项
     */
    public void done(SaleReturn saleReturn) {
        //占款未清项减少(去除返利金)
        charge(saleReturn, "occupy_unsettled", -1 * saleReturn.getAmtTotal() + saleReturn.getDiscount());
    }


    /**
     * 写入总账
     */
    private void transaction(SaleReturn saleReturn, Object... items) {
        ledgerService.transaction(saleReturn.getCompany(), saleReturn.getDept(), saleReturn.getCustomer(),
                saleReturn.getCooperation().getInventoryMode(), saleReturn.getCooperation().getAccountingMethod(),
                saleReturn.getId(), saleReturn.getInnerBusinessType(), new Date(), items);
    }

    /**
     * 写入总账
     */
    private void charge(SaleReturn saleReturn, String ledgerAccount, Double incurred) {
        ledgerService.charge(saleReturn.getCompany(), saleReturn.getDept(), saleReturn.getCustomer(),
                saleReturn.getCooperation().getInventoryMode(), saleReturn.getCooperation().getAccountingMethod(),
                saleReturn.getId(), saleReturn.getClass().getSimpleName(), new Date(), ledgerAccount, incurred);
    }

    /**
     * 可用数（仅仅处理提单冲红）
     */
    private void productAccountService(SaleReturn saleReturn, SaleReturnItem saleReturnItem, Double unit, String remarks) {
        productAccountService.setProductAvailable(saleReturnItem.getProduct(),
                saleReturn.getLocation(), saleReturnItem.getUom(), unit * saleReturnItem.getQtyDelivering(), saleReturn.getInnerBusinessType(), saleReturn.getId(), saleReturnItem.getId(), remarks, saleReturn.getCompany());
    }

    /***
     * 退货数量（退货中/已退货）
     */
    private void setQtyReturning(SaleReturn saleReturn, Double unit) {
        SaleOrder saleOrder = saleReturn.getSaleOrder();
        saleReturn.getSaleReturnItems().stream().forEach(saleReturnItem -> {
            SaleOrderItem saleOrderItem = saleOrder.getSaleItems().stream().filter(
                    item -> item.getId().equals(saleReturnItem.getSaleOrderItem().getId())
            ).findFirst().get();
            if (unit != null) {
                saleOrderItem.sumQtyReturning(unit * saleReturnItem.getQtyDelivering(), unit * saleReturnItem.getQtyDelivered());
                saleReturnItem.sumProductUomQty();
            } else {
                // 释放提单冲红数量 退货冲红数量  写入退货数量
                saleOrderItem.sumQtyReturning(-1 * saleReturnItem.getQtyDelivering(), -1 * saleReturnItem.getQtyDelivered());
                saleOrderItem.calcQtyReturned(saleReturnItem.getProductUomQty());
                saleOrderItem.cancle(saleReturnItem.getQtyDelivering());
            }
        });

        saleOrderRepository.save(saleOrder);
    }

    private void setQtyReturned(SaleReturn saleReturn) {
        setQtyReturning(saleReturn, null);
    }

    /**
     * 交货单冻结/解冻(提单冲红数量)
     */
    private void frost(SaleReturn saleReturn, Double unit) {
        JSONObject tempJson = new JSONObject();
        tempJson.put("id", saleReturn.getSaleOrder().getId());
        tempJson.put("innerBusinessType", saleReturn.getSaleOrder().getInnerBusinessType());
        List<Map> items = saleReturn.getSaleReturnItems().stream()
                .filter(saleReturnItem -> saleReturnItem.getQtyDelivering() > 0 && checkPicked(saleReturnItem))
                .map(saleReturnItem -> {
                    Map pickItem = new HashMap();
                    pickItem.put("id", saleReturnItem.getSaleOrderItem().getId());
                    pickItem.put("frostQty", unit * saleReturnItem.getQtyDelivering());
                    return pickItem;
                }).collect(Collectors.toList());
        if (items.size() == 0) return;
        tempJson.put("items", items);
        this.invoke("stock.pick.frost", tempJson);
    }

    /**
     * 交货单终止
     */
    private void pickCancel(SaleReturn saleReturn) {
        JSONObject tempJson = new JSONObject();
        tempJson.put("id", saleReturn.getSaleOrder().getId());
        tempJson.put("innerBusinessType", saleReturn.getSaleOrder().getInnerBusinessType());
        List<Map> items = saleReturn.getSaleReturnItems().stream()
                .filter(saleReturnItem -> saleReturnItem.getQtyDelivering() > 0 &&checkPicked(saleReturnItem))
                .map(saleReturnItem -> {
                    Map pickItem = new HashMap();
                    pickItem.put("id", saleReturnItem.getSaleOrderItem().getId());
                    pickItem.put("cancelQty", saleReturnItem.getQtyDelivering());
                    return pickItem;
                }).collect(Collectors.toList());
        if (items.size() == 0) return;
        tempJson.put("items", items);
        this.invoke("stock.pick.cancel", tempJson);
    }



    private List<String> queryRole(SimpleRequest request){
        String topic = "event:aut.post.findLocalPermitItems";
//        List<PartyRole> roleList = new ArrayList<>();
        Map body = MapUtil.mapper("postId", request.getPostId(), "purpose", "pp_search", "type", "pt_dept");
        List<String> orgIds = (List<String>) EventUtil.sendSynEvent(this, topic, body).stream().findFirst().get();
//        if(orgIds.isEmpty()){
//            roleList.addAll(partyRoleRepository.findAllCompany());
//        }
        return orgIds;
    }

    /***
     * 功能：findOne
     * @param request
     * @return
     */
    public SaleReturn findOne(SimpleRequest request) {
        Map params = MapUtil.mapper("orderType.code", "A", "id", request.get("id"));
        List<SaleReturn> list = saleReturnRepository.findAll(JpaDsl.toCriteria(params));
        if (list != null && list.size() > 0) return list.get(0);
        return null;
    }


    // 创建交货单
    public Pick createPickOrder(SimpleRequest request) {
        SaleReturn saleReturn = request.getO(SaleReturn.class);
        Pick pick = new Pick();
        pick.setMoveType(saleReturn.getMoveType());        // 交货方式 direct：部分交货，one： 一次性交货
        pick.setCompany(saleReturn.getCompany());    // 设置公司
        pick.setLocation(saleReturn.getLocation());                // 设置仓库
        pick.setPartner(saleReturn.getCustomer());              // 合作伙伴 收货方的公司

        pick.setOrigin(saleReturn.getId());
        pick.setOriginBusinessType(saleReturn.getInnerBusinessType());
        pick.setOperation("receipt");                   // 交货类型：收货

        pick.setScene(saleReturn.getScene());                // 注入场景
        pick.setPickItems(createPickOrderItem(saleReturn));          // 添加明细

        return pick;
    }


    private Set<PickItem> createPickOrderItem(SaleReturn saleReturn) {
        Set<PickItem> pickItems = saleReturn.getSaleReturnItems().stream()
                .filter(saleReturnItem -> LogicalUtil.notIn(saleReturnItem.getProduct().getType(), "aut") && saleReturnItem.getQtyDelivered() > 0)
                .map(saleReturnItem -> {
                    PickItem pickItem = new PickItem();
                    pickItem.setProduct(saleReturnItem.getProduct());
                    pickItem.setUom(saleReturnItem.getUom());
                    pickItem.setOrderedQty(saleReturnItem.getQtyDelivered());
                    pickItem.setProductUomQty(saleReturnItem.getQtyDelivered());
                    pickItem.setOriginLine(saleReturnItem.getId());
                    return pickItem;
                }).collect(Collectors.toSet());
        return pickItems;
    }


    /**
     * 功能：处理收货完成事件
     */
    @Listener(topic = "event:stock.pick.delivery")
    public void delivery(SimpleRequest request) {
        JSONObject param = request.getJO();
        if (!param.getString("originBusinessType").equals(SaleReturn.class.getSimpleName())) return;
        SaleReturn saleReturn = saleReturnRepository.findOne(param.getString("origin"));
        for (Map item : ((List<Map>) param.get("items"))) {
            saleReturn.getSaleReturnItems().stream()
                    .filter(saleReturnItem -> saleReturnItem.getId().equals((String) item.get("originItemId")))
                    .forEach(saleReturnItem -> {
                        double qtyDone = ((Number) item.get("qtyDone")).doubleValue();
                        // 写入收货数量
                        saleReturnItem.delivery(qtyDone);
                    });
        }
        // 更新交货状态以及单据状态
        saleReturn.setShipped();

        // 用于判断是否触发场景流
        if (saleReturn.getState().equals("confirmed")) saleReturnRepository.save(saleReturn);
        if (saleReturn.getState().equals("done")) saleReturnRepository.saveAndFlush(saleReturn);
    }

    /**
     * 是否需要发货
     *
     * @param saleReturnItem
     * @return
     */
    private boolean checkPicked(SaleReturnItem saleReturnItem) {
        return saleReturnItem.getSaleOrderItem().getProductRule() == 0;
    }


}
